package cn.b.sky.mes.mm.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import cn.b.sky.mes.mm.enums.DistributionStatus;
import cn.b.sky.mes.mm.enums.DistributionTriggerModeEnums;
import cn.b.sky.mes.mm.enums.RequirementStatus;
import cn.b.sky.mes.mm.model.Distribution;
import cn.b.sky.mes.mm.model.PFEP;
import cn.b.sky.mes.mm.model.Requirement;
import cn.b.sky.mes.mm.model.RequirementDistribution;
import cn.b.sky.mes.mm.service.SafetyinventroyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.b.sky.mes.mm.dao.DistributionDao;
import cn.b.sky.mes.mm.dao.InventoryDao;
import cn.b.sky.mes.mm.dao.PFEPDao;
import cn.b.sky.mes.mm.dao.RequirementDao;
import cn.b.sky.mes.mm.dao.RequirementdistributionDao;
import cn.b.sky.mes.mm.dao.SafetyinventroyDao;
import cn.b.sky.mes.mm.model.Safetyinventroy;
import cn.b.sky.mes.mm.service.DistributionTacticsService;
import cn.b.sky.mes.cm.enums.NumberRuleEnums;
import cn.b.sky.user.service.NumberRuleService;

/**
 * 
 * <strong>Title : DistributionTacticsServiceImpl.java<br></strong>
 * <strong>Package : cn.b.sky.mes.mm.service.impl<br></strong>
 * <strong>Description : </strong>配送策略接口实现<br> 
 * <strong>Create on : 2016-9-21 下午6:46:37<br></strong>
 * <p>
 * @author JinQuan.Fu<br>
 * @version <strong>v1.0.0</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人|修改日期|修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 */
@Service("distributionTacticsService")
public class DistributionTacticsServiceImpl implements DistributionTacticsService {

  @Autowired
  private SafetyinventroyDao safetyinventroyDao;
  
  @Autowired
  RequirementDao requirementDao;

  @Resource
  InventoryDao inventoryDao;
  
  @Resource
  PFEPDao pFEPDao;
  
  @Resource
  DistributionDao distributionDao;
  
  @Resource
  RequirementdistributionDao requirementdistributionDao;
  
  @Resource
  NumberRuleService numberRuleService;
  
  @Override
  public void doCreateDirectDistributionTaskJob(String siteCode) {
    //查询物料需求单     配送需求触发策略为：直接配送、状态：创建、 已配送数量  小于  需求数量    
    List<Requirement> requirementList = requirementDao.getRequirementBySafetyinventroy(siteCode,
        DistributionTriggerModeEnums.DIRECTDISTRIBUTION.getDistributionTriggerModeCode(), RequirementStatus.CREATED.getStatus());
    //已线边库、库位、物料编号、配送形式、配送人为key进行分类
    Map<String, List<Requirement>>  materialMap = this.listRequirementsToMap(requirementList,
        DistributionTriggerModeEnums.DIRECTDISTRIBUTION.getDistributionTriggerModeCode());
    //循环
    for(String key : materialMap.keySet()){
      List<Requirement> list = materialMap.get(key);
      if(list!=null){
        //获取PFEP:单次配送量
        PFEP pfep = pFEPDao.selectPFEP(siteCode, list.get(0).getMaterialCode());
        if (pfep !=null) {
          Double quantity = 0.0; 
          Double distributionQuantity = pfep.getDistributionQuantity();
          List<Requirement> requirements =new ArrayList<Requirement>();
          List<Distribution> distributions =new ArrayList<Distribution>();
          for (int i = 0; i < list.size(); i++) {              
            quantity = quantity + list.get(i).getRequirementQuantity(); 
            requirements.add(list.get(i));
            if(quantity >= distributionQuantity){          
              Double count = Math.floor(quantity/distributionQuantity);    
              for (int j = 1; j <= count; j++) {
                Distribution distribution = insertDistribution(list.get(i),distributionQuantity);
                distributions.add(distribution);                       
              }       
              quantity = quantity-(distributionQuantity * count); 
              requirements=insertRequirementdistribution(requirements, distributions,distributionQuantity,siteCode);
            }     
          }
        }
      }
    }
  };
  
  /**
   * <strong>Title : doCreateDistributionRequirementTaskJob<br></strong>
   * <strong>Description : </strong>配送策略-安全库存<br> 
   * <strong>Create on : 2016-9-21 下午1:07:26<br></strong>
   * <p>
   * @param siteCode
   * @see SafetyinventroyService#doCreateDistributionRequirementTaskJob(java.lang.String)
   * @throws 
   * @author JinQuan.Fu<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  @Override
  public void doCreateSafetyInventroyTaskJob(String siteCode) {
    //查询物料需求单     配送需求触发策略为：安全库存、状态：创建、 已配送数量  小于  需求数量    
    List<Requirement> requirementList = requirementDao.getRequirementBySafetyinventroy(siteCode,
        DistributionTriggerModeEnums.SAFETYINVENTROY.getDistributionTriggerModeCode(),RequirementStatus.CREATED.getStatus());             
    //已物料、仓库、库位为key进行分类
    Map<String, List<Requirement>>  materialMap = this.listRequirementsToMap(requirementList,DistributionTriggerModeEnums.SAFETYINVENTROY.getDistributionTriggerModeCode());
    //循环
    for(String key : materialMap.keySet()){
      List<Requirement> list = materialMap.get(key);
      if(list!=null){
        Requirement requirement = list.get(0);
        //①取安全库存 
        Safetyinventroy safetyinventroy =safetyinventroyDao.selectSafetyinventroy(siteCode, requirement.getMaterialCode(),
            requirement.getWarehouseCode(), requirement.getStorageLocationCode());       
        if (safetyinventroy == null) {
          continue;
        }
        Double safetyStock =safetyinventroy.getSafetyInventory();
        //②取库存明细中现有库存        
        Double existingStocks = inventoryDao.getInventory(requirement);
        //③取状态为：创建 的 需配数量总和
        Double dispensedQuantity =  distributionDao.groupMaterialDistributionQuantity(siteCode, requirement.getMaterialCode(),
            requirement.getWarehouseCode(), requirement.getStorageLocationCode(),RequirementStatus.CREATED.getStatus());
        //判断触发配送需求：  ② + ③ < ①
        if((existingStocks+dispensedQuantity) < safetyStock){
          //获取PFEP:单次配送量
          PFEP pfep = pFEPDao.selectPFEP(siteCode, requirement.getMaterialCode());
          if (pfep !=null) {
            Double quantity = 0.0; 
            Double distributionQuantity = pfep.getDistributionQuantity();
            List<Requirement> requirements =new ArrayList<Requirement>();
            List<Distribution> distributions =new ArrayList<Distribution>();
            for (int i = 0; i < list.size(); i++) {              
              quantity = quantity + list.get(i).getRequirementQuantity(); 
              requirements.add(list.get(i));
              if(quantity >= distributionQuantity){          
                Double count = Math.floor(quantity/distributionQuantity);    
                for (int j = 1; j <= count; j++) {
                  Distribution distribution = insertDistribution(list.get(i),distributionQuantity);
                  distributions.add(distribution);                       
                }       
                quantity = quantity-(distributionQuantity * count); 
                requirements=insertRequirementdistribution(requirements, distributions,distributionQuantity,siteCode);
              }     
            }       
          }
        }
      }
    }    
  }
   
  /**
   * 
   * <strong>Title : insertRequirementdistribution<br></strong>
   * <strong>Description : </strong>生成需求配送关联关系记录<br> 
   * <strong>Create on : 2016-9-21 下午1:06:13<br></strong>
   * <p>
   * @param requirements
   * @param distributions
   * @param distributionQuantity
   * @param siteCode
   * @return
   * List<Requirement>
   * @throws 
   * @author JinQuan.Fu<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  private List<Requirement> insertRequirementdistribution(List<Requirement> requirements,List<Distribution> distributions,Double distributionQuantity,String siteCode) {
    RequirementDistribution requirementdistribution = new RequirementDistribution();
    requirementdistribution.setSiteCode(siteCode);
    requirementdistribution.setCreateDateTime(new Date());
    requirementdistribution.setCreateUser(requirements.get(0).getCreateUser());
    //一对一
    if (requirements.size() == 1 && distributions.size() == 1) {      
      requirementdistribution.setRequirementNum(requirements.get(0).getRequirementNum());
      requirementdistribution.setRequirementQuantity(distributionQuantity);
      requirementdistribution.setDistributionNum(distributions.get(0).getDistributionNum());
      requirementdistribution.setDistributionQuantity(distributionQuantity);
      requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
      requirementDao.updateRequirementDistributionquantity(requirements.get(0).getSiteCode(), requirements.get(0).getRequirementNum(), 
          requirements.get(0).getDistributionQuantity()+distributionQuantity);
      requirements.get(0).setDistributionQuantity(requirements.get(0).getDistributionQuantity()+distributionQuantity);
      if(requirements.get(0).getRequirementQuantity()-distributionQuantity == 0 ){
        requirements.clear();
      }else {
        requirements.get(0).setRequirementQuantity(requirements.get(0).getRequirementQuantity()-distributionQuantity);         
      }
      distributions.clear();
    }
    //多对一
    else if (requirements.size() >1 && distributions.size()== 1) {
      Double quantity = 0.0;    
      for (int i = 0; i < requirements.size(); i++) {        
        quantity=quantity+requirements.get(i).getRequirementQuantity();
        requirementdistribution.setRequirementNum(requirements.get(i).getRequirementNum());
        requirementdistribution.setDistributionNum(distributions.get(0).getDistributionNum());                       
        if(i==requirements.size()-1){   
          requirementdistribution.setRequirementQuantity(requirements.get(i).getRequirementQuantity()-(quantity-distributionQuantity));    
          requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
          requirementDao.updateRequirementDistributionquantity(requirements.get(i).getSiteCode(), requirements.get(i).getRequirementNum(), 
              requirements.get(i).getDistributionQuantity()+requirementdistribution.getRequirementQuantity());
          if(quantity-distributionQuantity ==0){
            requirements.clear();
          }else {
            requirements.get(i).setDistributionQuantity(requirements.get(i).getRequirementQuantity()-(quantity-distributionQuantity));
            requirements.get(i).setRequirementQuantity(quantity-distributionQuantity);            
          }           
        }else { 
          requirementdistribution.setRequirementQuantity(requirements.get(i).getRequirementQuantity()); 
          requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
          requirementDao.updateRequirementDistributionquantity(requirements.get(i).getSiteCode(), requirements.get(i).getRequirementNum(), 
              requirements.get(i).getDistributionQuantity()+requirementdistribution.getRequirementQuantity()); 
          requirements.remove(0);
          i--;          
        }                
      }
      distributions.clear();
    }
    //一对多
    else if (requirements.size()==1 && distributions.size()> 1) {
      for (Distribution distribution : distributions) {
        requirementdistribution.setRequirementNum(requirements.get(0).getRequirementNum());
        requirementdistribution.setDistributionNum(distribution.getDistributionNum());
        requirementdistribution.setDistributionQuantity(distribution.getDistributionQuantity());
        requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
        requirementDao.updateRequirementDistributionquantity(requirements.get(0).getSiteCode(), requirements.get(0).getRequirementNum(), 
            requirements.get(0).getDistributionQuantity()+distribution.getDistributionQuantity());
        requirements.get(0).setDistributionQuantity(requirements.get(0).getDistributionQuantity()+distribution.getDistributionQuantity());
      }
      if(requirements.get(0).getRequirementQuantity()- distributions.size()*distributionQuantity ==0){
        requirements.clear();
      }else {
        requirements.get(0).setRequirementQuantity(requirements.get(0).getRequirementQuantity()- distributions.size()*distributionQuantity);
      }
      distributions.clear();
    }
    //多对多
    else if (requirements.size() >1 && distributions.size()> 1) {
      for (Distribution distribution : distributions) {
        Double quantity = 0.0;
        for (int i = 0; i < requirements.size(); i++) {
          quantity= quantity + requirements.get(i).getRequirementQuantity();
          if(quantity<distribution.getDistributionQuantity()){
            requirementdistribution.setRequirementNum(requirements.get(i).getRequirementNum());
            requirementdistribution.setRequirementQuantity(requirements.get(i).getRequirementQuantity());
            requirementdistribution.setDistributionNum(distribution.getDistributionNum());   
            requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
            requirementDao.updateRequirementDistributionquantity(requirements.get(i).getSiteCode(), requirements.get(i).getRequirementNum(), 
                requirements.get(i).getDistributionQuantity()+requirements.get(i).getRequirementQuantity());  
            requirements.remove(0);
            i--;
          }else {
            requirementdistribution.setRequirementNum(requirements.get(i).getRequirementNum());
            requirementdistribution.setRequirementQuantity(distributionQuantity-(quantity-requirements.get(i).getRequirementQuantity()));
            requirementdistribution.setDistributionNum(distribution.getDistributionNum());     
            requirementdistributionDao.insertRequirementDistribution(requirementdistribution);
            requirementDao.updateRequirementDistributionquantity(requirements.get(i).getSiteCode(), requirements.get(i).getRequirementNum(), 
                requirements.get(i).getDistributionQuantity()+requirementdistribution.getRequirementQuantity());             
            requirements.get(i).setDistributionQuantity(requirements.get(i).getDistributionQuantity()+requirementdistribution.getRequirementQuantity());
            requirements.get(i).setRequirementQuantity(quantity - distributionQuantity);
            if(quantity - distributionQuantity==0){
              requirements.remove(0);
            }
            break;
          }
        }
      }
      distributions.clear();
    }
    return requirements;
  }
  
  /**
   * 
   * <strong>Title : insertDistribution<br></strong>
   * <strong>Description : </strong>添加配送单<br> 
   * <strong>Create on : 2016-9-21 下午1:06:05<br></strong>
   * <p>
   * @param requirement
   * @param distributionQuantity
   * @return
   * Distribution
   * @throws 
   * @author JinQuan.Fu<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  private Distribution insertDistribution(Requirement requirement,Double distributionQuantity) {
    Distribution distribution = new Distribution();
    distribution.setSiteCode(requirement.getSiteCode());
    distribution.setCreateDateTime(new Date());
    distribution.setCreateUser(requirement.getCreateUser());
    distribution.setModifyDateTime(new Date());
    distribution.setModifyUser(requirement.getCreateUser());
    distribution.setDistributionNum(numberRuleService.selectNextNumber(requirement.getSiteCode(),
            NumberRuleEnums.DISTRIBUTIONNUM.getValue()));
    distribution.setMaterialCode(requirement.getMaterialCode());
    distribution.setDistributionQuantity(distributionQuantity);    
    distribution.setDistributionModeCode(requirement.getDistributionModeCode());
    distribution.setPullStrategyCode(requirement.getPullStrategyCode());
    distribution.setRequirementTriggerModeCode(requirement.getRequirementTriggerModeCode());
    distribution.setDistributionTriggerModeCode(requirement.getDistributionTriggerModeCode());
    distribution.setStatusECode(DistributionStatus.CREATED.getStatus());
    distribution.setWorkCenterCode(requirement.getWorkcenterCode());
    distribution.setWorkUnitCode(requirement.getWorkunitCode());
    distribution.setWarehouseCode(requirement.getWarehouseCode());
    distribution.setLocationCode(requirement.getStorageLocationCode());   
    distribution.setDistributionUser(requirement.getDistributionUser());
    distributionDao.insertDistribution(distribution);    
    return distribution;  
  }

  /**
   * 
   * <strong>Title : listRequirementsToMap<br></strong>
   * <strong>Description : </strong>按照物料、仓库、库位为key进行Map分类<br> 
   * <strong>Create on : 2016-9-18 下午3:51:35<br></strong>
   * <p>
   * @param requirements
   * @return
   * Map<String,List<Requirement>>
   * @throws 
   * @author JinQuan.Fu<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public Map<String, List<Requirement>> listRequirementsToMap(List<Requirement> requirements,String state){
    Map<String, List<Requirement>>  materialMap = new HashMap<String, List<Requirement>>();  
    List<Requirement> list;
    for (Requirement requirement : requirements) {
      String key;
      if(DistributionTriggerModeEnums.SAFETYINVENTROY.getDistributionTriggerModeCode().equals(state)){
        key=requirement.getMaterialCode() + requirement.getWarehouseCode() + requirement.getStorageLocationCode();
      }else if(DistributionTriggerModeEnums.DIRECTDISTRIBUTION.getDistributionTriggerModeCode().equals(state)){
        key =requirement.getMaterialCode() + requirement.getWarehouseCode() + requirement.getStorageLocationCode()
           +requirement.getDistributionModeCode()+requirement.getDistributionUser() ;
      }else {
        key=requirement.getMaterialCode();
      }
      if( materialMap.get(key) == null){
        list =new ArrayList<Requirement>();
        list.add(requirement);
        materialMap.put(key, list);
      }else {
        list =materialMap.get(key);
        list.add(requirement);
        materialMap.put(key, list);
      }
    }
    return materialMap;
  }
  
}
